package routers

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"net/http"
	"sensi/common/frame"
	"sensi/common/sys"
	"sensi/common/sys/database"
	"sensi/common/sys/logger"
)

type errorResponse interface {
	Code() int
	Msg() string
	Data() interface{}
}

// Response ...
type Response struct {
	Error
	Data interface{} `json:"data"`
}

type Error struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Status  int    `json:"status"`
	Msg     string `json:"msg"`
}

// InitRouter ...
func InitRouter() *gin.Engine {
	r := gin.New()
	r.Use(logger.Middleware())
	r.Use(gin.Recovery())
	r.Use(func(ctx *gin.Context) {
		method := ctx.Request.Method
		ctx.Header("Access-Control-Allow-Origin", sys.CORSOrigin)
		ctx.Header("Access-Control-Allow-Credentials", "true")
		ctx.Header("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS")
		ctx.Header("Access-Control-Expose-Headers", "*")
		ctx.Header("Access-Control-Allow-Headers", "content-type")

		if method == "OPTIONS" {
			ctx.AbortWithStatus(http.StatusNoContent)
		}
		ctx.Next()
	})
	r.Use(database.Middleware())

	serve(r)
	return r
}

func route(handle func(ctx *gin.Context) (interface{}, error)) func(ctx *gin.Context) {
	return func(ctx *gin.Context) {
		resp := Response{}
		status := http.StatusOK
		data, err := handle(ctx)
		if err != nil {
			if resper, ok := err.(errorResponse); ok {
				resp.Code = resper.Code()
				resp.Message = resper.Msg()
				resp.Data = resper.Data()
				_ = ctx.Error(fmt.Errorf("code: %s, msg: %s, data: %v", resper.Code(), resper.Msg(), resper.Data()))
			} else if err1, ok := err.(validator.ValidationErrors); ok {
				resp.Code = 401
				resp.Message = err1.Error()
			} else {
				resp.Code = 500
				resp.Message = "InternalServerError"
				if sys.Env == frame.EnvDevelopment {
					resp.Data = err.Error()
				}
				_ = ctx.Error(err)
			}

		} else {
			resp.Data = data
		}

		resp.Status = resp.Code
		resp.Msg = resp.Message
		ctx.JSON(status, resp)
	}
}
